#include "input_buf.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "def.h"
#include "log.h"

/**
 * @brief 申请一个input_buf
 *
 * @param path input_buf读取的文件路径
 * @return input_buf_st* 申请得到的input_buf指针
 */
input_buf_st *input_buf_malloc(
    char *path)
{
    if (STR_EMPTY(path))
    {
        NOTICE("path is NULL\n");
        return NULL;
    }
    input_buf_st *input_buf = my_calloc(1, sizeof(input_buf_st));
    if (input_buf == NULL)
    {
        ERR("calloc input_buf failed!\n");
        return NULL;
    }

    if (strlen(path) > sizeof(input_buf->path))
    {
        ERR_FUNC_LINE("path to long!\n");
        input_buf_free(input_buf);
        return NULL;
    }
    strcpy(input_buf->path, path);

    input_buf->fp = fopen(input_buf->path, "r");
    if (input_buf->fp == NULL)
    {
        ERR("fopen err: %s", strerror(errno));
        input_buf_free(input_buf);
        return NULL;
    }

    return input_buf;
}

/**
 * @brief 释放input_buf
 *
 * @param input_buf 待释放的input_buf指针
 */
void input_buf_free(
    input_buf_st *input_buf)
{
    if (input_buf == NULL)
    {
        NOTICE("input buf is NULL\n");
    }

    if (input_buf->fp != NULL)
    {
        fclose(input_buf->fp);
    }

    my_free(input_buf);
}

/**
 * @brief 从input_buf中读取一个字符
 *
 * @param input_buf 读取的input_buf结构体的指针
 * @return uint8_t 返回读取的字符 没有读到字符，则返回'\0'
 */
uint8_t input_buf_get_char(
    input_buf_st *input_buf)
{
    if (input_buf == NULL)
    {
        ERR("input buf is NULL\n");
        return '\0';
    }

    /* 缓冲区没有数据 */
    if (input_buf->get_posi == input_buf->put_posi)
    {
        /* put_posi不处于buff起始或者中间，说明此前已经读取到文件尾，不再读取数据 */
        if (input_buf->put_posi % (sizeof(input_buf->buff) / 2))
        {
            return '\0';
        }

        uint32_t read_len = fread(&(input_buf->buff[input_buf->put_posi]),
                                  sizeof(uint8_t), sizeof(input_buf->buff) / 2, input_buf->fp);

        if (read_len == 0)
        {
            return '\0';
        }
        input_buf->fread_len += read_len;
        input_buf->put_posi += read_len;
        input_buf->put_posi = (input_buf->put_posi) % sizeof(input_buf->buff);
    }

    uint8_t ret = input_buf->buff[input_buf->get_posi];
    input_buf->get_posi++;
    input_buf->get_posi = input_buf->get_posi % sizeof(input_buf->buff);
    return ret;
}

/**
 * @brief get_posi回退一个字节
 *
 * @param input_buf 需要回退的input_buf结构体指针
 * @return int32_t 0:回退成功; < 0:回退失败
 */
int32_t input_buf_goback(
    input_buf_st *input_buf)
{
    if (input_buf->fread_len == 0)
    {
        return -1;
    }

    if (input_buf->get_posi == 0)
    {
        input_buf->get_posi = sizeof(input_buf->buff) - 1;
    }
    else
    {
        input_buf->get_posi--;
    }
    return 0;
}

/**
 * @brief  input_buf测试函数
 *
 */
void input_buf_test(
    void)
{
    FUNC_BEGIN();
    char *path = "./test_data.txt";
    input_buf_st *input_buf = input_buf_malloc(path);
    assert(input_buf != NULL);

    NOTICE_FUNC_LINE("input_buf_get_char:\n");
    uint8_t get_char = '\0';
    while ('\0' != (get_char = input_buf_get_char(input_buf)))
    {
        NOTICE("%c", get_char);
    }
    NOTICE("\n");

    input_buf_free(input_buf);
    input_buf = NULL;
    FUNC_FINISH();
}